#include <ConfigInit.h>
/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2021-07-03     ThinkPad       the first version
 */
#include <rtthread.h>
#include <rtdevice.h>
#include "drv_common.h"
#include <dfs_posix.h>
#include <../utils/cJSON.h>
#include <ComApp0.h>
#include <ComApp3.h>
#include <ComApp4.h>
#include <ComApp5.h>


#define CONFIG_FILE ("/config.json")


int g_fdConfig = -1;

/* 用于接收消息的信号量 */
struct rt_semaphore g_sem_sd;

static cJSON *root = RT_NULL;

static void configinit_thread_entry(void *parameter)
{
    rt_kprintf("waiting for sem sd from configInit\n");
    rt_sem_take(&g_sem_sd, RT_WAITING_FOREVER);


    if (-1 == access("/serial_data", 0))  // if not exists the dir, create it
    {
        mkdir("/serial_data", 0x777);
    }

    if (-1 == access("udp_data", 0)) // if not exists the dir, create it
    {
        mkdir("/udp_data", 0x777);
    }

    rt_kprintf("get sem of sd from configInit\n");
    rt_sem_release(&g_sem_sd);
//    return;

    if (g_fdConfig < 0)
    {
            g_fdConfig = open(CONFIG_FILE, O_RDWR | O_CREAT);
            rt_kprintf("\nopen config file failed, recreate\n");

            if (g_fdConfig >= 0)
            {
                char buf[2048] = {0};
                int nRead = read(g_fdConfig, buf, 2048);
                rt_kprintf("nRead: %d\n", nRead);
                /// if no config file, create it and then init it.
                if (nRead == 0)
                {
                    rt_kprintf("config file is new, init it.\n");
                    root = cJSON_CreateArray();
                    cJSON *com1, *com2, *com3, *com4, *com5;
                    com1 = cJSON_CreateObject();
                    com2 = cJSON_CreateObject();
                    com3 = cJSON_CreateObject();
                    com4 = cJSON_CreateObject();
                    com5 = cJSON_CreateObject();


                    // com1
                    cJSON_AddNumberToObject(com1, "baudrate", 614400);  // 614400, 115200
//                    cJSON_AddNumberToObject(com1, "stopbit", 1);
//                    cJSON_AddNumberToObject(com1, "databit", 8);
                    cJSON_AddNumberToObject(com1, "parity", 0);
                    cJSON_AddNumberToObject(com1, "switchx", 1);
                    cJSON_AddNumberToObject(com1, "period", 100); // 10ms 20ms 50ms 100ms
                    cJSON_AddNumberToObject(com1, "datalen", 10); // 10 to 800 by 1
                    cJSON_AddNumberToObject(com1, "dl_send", -1); // data len for send, no use here
                    cJSON_AddNumberToObject(com1, "dl_recv", -1); // data len for recv, no use here
                    cJSON_AddNumberToObject(com1, "head_1", -1);
                    cJSON_AddNumberToObject(com1, "head_2", -1);
                    cJSON_AddNumberToObject(com1, "head_3", -1);
                    cJSON_AddNumberToObject(com1, "ind", 0);


                    // com2
                    cJSON_AddNumberToObject(com2, "baudrate", 9600); // 9600 ~ 921600
//                    cJSON_AddNumberToObject(com2, "stopbit", 1);
//                    cJSON_AddNumberToObject(com2, "databit", 8);
                    cJSON_AddNumberToObject(com2, "parity", 0);
                    cJSON_AddNumberToObject(com2, "switchx", 1);
                    cJSON_AddNumberToObject(com2, "period", 20); // 10ms 20ms
                    cJSON_AddNumberToObject(com2, "datalen", 10); // 10 to 120 by 1
                    cJSON_AddNumberToObject(com2, "dl_send", -1); // data len for send, no use here
                    cJSON_AddNumberToObject(com2, "dl_recv", -1); // data len for recv, no use here
                    cJSON_AddNumberToObject(com2, "head_1", 126);
                    cJSON_AddNumberToObject(com2, "head_2", 126);
                    cJSON_AddNumberToObject(com2, "head_3", 126);
                    cJSON_AddNumberToObject(com2, "ind", 1);

                    // com3
                    cJSON_AddNumberToObject(com3, "baudrate", 9600); // 9600 ~ 921600
//                    cJSON_AddNumberToObject(com3, "stopbit", 1);
//                    cJSON_AddNumberToObject(com3, "databit", 8);
                    cJSON_AddNumberToObject(com3, "parity", 0);
                    cJSON_AddNumberToObject(com3, "switchx", 1);
                    cJSON_AddNumberToObject(com3, "period", 20); // 10ms 20ms
                    cJSON_AddNumberToObject(com3, "datalen", 10); // 10 to 120 by 1
                    cJSON_AddNumberToObject(com3, "dl_send", -1); // data len for send, no use here
                    cJSON_AddNumberToObject(com3, "dl_recv", -1); // data len for recv, no use here
                    cJSON_AddNumberToObject(com3, "head_1", 126);
                    cJSON_AddNumberToObject(com3, "head_2", 126);
                    cJSON_AddNumberToObject(com3, "head_3", 126);
                    cJSON_AddNumberToObject(com3, "ind", 2);

                    // com4
                    cJSON_AddNumberToObject(com4, "baudrate", 9600); // 9600 ~ 921600
//                    cJSON_AddNumberToObject(com4, "stopbit", 1);
//                    cJSON_AddNumberToObject(com4, "databit", 8);
                    cJSON_AddNumberToObject(com4, "parity", 0);
                    cJSON_AddNumberToObject(com4, "switchx", 1);
                    cJSON_AddNumberToObject(com4, "period", 20); // 10ms 20ms
                    cJSON_AddNumberToObject(com4, "datalen", -1); // no use here
                    cJSON_AddNumberToObject(com4, "dl_send", 10); // data len for send, 10 ~ 120
                    cJSON_AddNumberToObject(com4, "dl_recv", 10); // data len for recv, 10 ~ 350
                    cJSON_AddNumberToObject(com4, "head_1", 126);
                    cJSON_AddNumberToObject(com4, "head_2", 126);
                    cJSON_AddNumberToObject(com4, "head_3", 126);
                    cJSON_AddNumberToObject(com4, "ind", 3);

                    // com5
                    cJSON_AddNumberToObject(com5, "baudrate", 9600); // 9600 ~ 921600
//                    cJSON_AddNumberToObject(com5, "stopbit", 1);
//                    cJSON_AddNumberToObject(com5, "databit", 8);
                    cJSON_AddNumberToObject(com5, "parity", 0);
                    cJSON_AddNumberToObject(com5, "switchx", 1);
                    cJSON_AddNumberToObject(com5, "period", 20); // 10ms 20ms
                    cJSON_AddNumberToObject(com5, "datalen", -1); // no use here
                    cJSON_AddNumberToObject(com5, "dl_send", 10); // data len for send, 10 ~ 120
                    cJSON_AddNumberToObject(com5, "dl_recv", 10); // data len for recv, 10 ~ 350
                    cJSON_AddNumberToObject(com5, "head_1", 126);
                    cJSON_AddNumberToObject(com5, "head_2", 126);
                    cJSON_AddNumberToObject(com5, "head_3", 126);
                    cJSON_AddNumberToObject(com5, "ind", 4);


                    cJSON_AddItemToArray(root, com1);
                    cJSON_AddItemToArray(root, com2);
                    cJSON_AddItemToArray(root, com3);
                    cJSON_AddItemToArray(root, com4);
                    cJSON_AddItemToArray(root, com5);

                    cJSON *udp = cJSON_CreateObject();
                    cJSON_AddNumberToObject(udp, "ind", 5);
                    cJSON_AddNumberToObject(udp, "len", 50);  /// unit is Mbit
                    cJSON_AddItemToArray(root, udp);

                    char* initFileContent = cJSON_Print(root);
                    write(g_fdConfig, initFileContent, strlen(initFileContent));
                    fsync(g_fdConfig);
                    free(initFileContent);
                }

                // if there is config file here, read it, load the info, config device.
                else
                {
                    root = cJSON_Parse(buf);
                    int nArraySize = cJSON_GetArraySize(root);
                    for (int i=0; i<nArraySize; ++i)
                    {
                        cJSON* oneComInfo = cJSON_GetArrayItem(root, i);
                        int nBaudRate = cJSON_GetObjectItem(oneComInfo, "baudrate")->valueint;
                        rt_kprintf("com index: %d\n",  i+1);
                        rt_kprintf("baudrate: %d\n", nBaudRate);
                        rt_kprintf("parity: %d\n\n", cJSON_GetObjectItem(oneComInfo, "parity")->valueint);

                        if (0 == i)
                        {
                            ComApp1();
                            DataConverge();
                        }
                        if (1 == i)
                        {
                            ComApp2();
                        }
                        else if (2 == i)
                        {
                            ComApp3();
                        }
                        else if (3 == i)
                        {
                            ComApp4();
                        }
                        else if (4 == i)
                        {
                            ComApp5();
                        }
                    }
                }

                close(g_fdConfig);
                g_fdConfig = -1;
            }

            else
            {
                rt_kprintf("create file failed again\n");
            }
        }

}



int ConfigInit()
{
    rt_err_t ret = RT_EOK;
    /* 初始化信号量 */
    rt_sem_init(&g_sem_sd, "gSDsem", 0, RT_IPC_FLAG_FIFO);

    /* 创建 serial 线程 */
    rt_thread_t thread = rt_thread_create("tSD", configinit_thread_entry, RT_NULL, 4096, 25, 10);
    /* 创建成功则启动线程 */
    if (thread != RT_NULL)
    {
        rt_kprintf("start tSD thread ok\n");
        rt_thread_startup(thread);
    }
    else
    {
        rt_kprintf("start tSD thread failed\n");
        ret = RT_ERROR;
    }


    return ret;
}


void* getComConfigRoot()
{
    return root;
}

rt_bool_t updateRoot()
{
    g_fdConfig = open(CONFIG_FILE, O_RDWR | O_CREAT);

   if (g_fdConfig >= 0)
   {
       char buf[2048] = {0};
       int nRead = read(g_fdConfig, buf, 2048);

       if (nRead > 0)
       {
           root = cJSON_Parse(buf);
           return RT_TRUE;
       }
       else
       {
        return RT_FALSE;
       }
   }
   else
   {
       return RT_FALSE;
   }
}

rt_bool_t updateFile(cJSON * config)
{
    g_fdConfig = open(CONFIG_FILE, O_WRONLY | O_TRUNC);
    if (g_fdConfig < 0)
    {
        return RT_FALSE;
    }

    char* initFileContent = cJSON_Print(config);
    write(g_fdConfig, initFileContent, strlen(initFileContent));
    fsync(g_fdConfig);
    free(initFileContent);
    return RT_TRUE;
}


